package dal

import (
	"context"

	"algo-sdk-go/framework/middleware/db/mongodb/dbops"
	"algo-sdk-go/project/matchmaking/adapter/convertor"
	"algo-sdk-go/project/matchmaking/common/constant"
	"algo-sdk-go/project/matchmaking/domain/models/entity"
	"algo-sdk-go/project/matchmaking/domain/port/repo/ops"
	"algo-sdk-go/project/matchmaking/matchMaking-api/config"

	"github.com/pkg/errors"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type MatePreferenceDal struct {
	MatePreferenceCollection *mongo.Collection
}

func NewMatePreferenceRepository(config *config.Config) *MatePreferenceDal {
	mc, err := mongo.Connect(context.Background(), options.Client().ApplyURI(config.Mongo.Url))
	if err != nil {
		panic(err)
	}

	return &MatePreferenceDal{
		MatePreferenceCollection: mc.Database(config.Mongo.DataBase).Collection(constant.MatePreferenceDBName),
	}
}

func (m *MatePreferenceDal) Save(ctx context.Context, matePreference *entity.MatePreference) (int, error) {
	poInfo := convertor.ConvertMatePreferenceToPo(matePreference)
	if _, err := m.MatePreferenceCollection.InsertOne(ctx, poInfo); err != nil {
		return constant.ErrorUserNum, err
	}
	return matePreference.UserNum, nil
}

func (m *MatePreferenceDal) Modify(ctx context.Context, matePreference *entity.MatePreference) error {
	matePreferencePo := convertor.ConvertMatePreferenceToPo(matePreference)

	if err := dbops.Valid(ops.MatePreferenceValid(matePreferencePo)); err != nil {
		return errors.WithMessage(err, "matePreferencePo_valid_error")
	}

	filter := dbops.GetFilter(
		ops.WithUserNum(matePreferencePo.UserNum, constant.DBUserNum),
	).AndOperator()

	updateInfo := dbops.GetUpdater(
		dbops.SetIntValue(constant.DBMinHeight, matePreferencePo.MinHeight),
		dbops.SetIntValue(constant.DBMaxWeight, matePreferencePo.MaxWeight),
	).Set()

	if _, err := m.MatePreferenceCollection.UpdateOne(ctx, filter, updateInfo); err != nil {
		return errors.Wrapf(err, "MatePreferenceDal Modify UpdateOne error, matePreferencePo: %+v", matePreferencePo)
	}
	return nil
}

func (m *MatePreferenceDal) LoadMatePreferenceByUserNums(ctx context.Context, userNumList []int) ([]entity.MatePreference, error) {
	filter := dbops.GetFilter(
		ops.WithUserNumsRemoveZero(userNumList, constant.DBUserNum),
	).AndOperator()

	return dbops.GetAllItemsFromMongo(ctx, m.MatePreferenceCollection, filter, nil, convertor.ConvertMatePreferenceToEntity)
}

func (m *MatePreferenceDal) LoadMatePreferenceByCondition(ctx context.Context, condition ops.Condition) ([]entity.MatePreference, error) {
	filter := dbops.GetFilter(
		ops.WithUserNumsRemoveZero(condition.UserNumList, constant.DBUserNum),
	).AndOperator()

	opts := dbops.GetOpts(
		dbops.SetSortBy(condition.SortBy, constant.DBUpdateTime),
		dbops.SetPageNumPageSize(condition.PageNum, condition.PageSize, condition.IgnorePage),
	).Get()

	return dbops.GetAllItemsFromMongo(ctx, m.MatePreferenceCollection, filter, opts, convertor.ConvertMatePreferenceToEntity)
}
